#pragma once

#include "runner_impl.hpp"

using namespace System;
using namespace Calculation;
using namespace System::Runtime::InteropServices;

namespace CppRunner 
{

public ref class Runner : CalculationRunner
{
private:
	double result;
	size_t size;
	CalculationProgress^ progress;

public:
	Runner(size_t size) : size(size) {}


	delegate bool CancellationPending();
	delegate void SetCurrentValue(double, unsigned long);

	bool CancellationPendingWrapper()
	{
		return progress->CancellationPending;
	}

	void SetCurrentValueWrapper(double value, unsigned long samples)
	{
		progress->SetCurrentResult(value, samples);
	}

	void Run(CalculationProgress^ progress) override
	{
		this->progress = progress;

		auto cancel = 
			gcnew CancellationPending(this, &Runner::CancellationPendingWrapper);

		auto setValue = 
			gcnew SetCurrentValue(this, &Runner::SetCurrentValueWrapper);

        IntPtr cancelUnmanaged = Marshal::GetFunctionPointerForDelegate(cancel);
		IntPtr setValueUnmanaged = Marshal::GetFunctionPointerForDelegate(setValue);
        
        RunnerImpl runner;

		result = runner.Run(size, 
			(RunnerImpl::CancelCallback)(void*)cancelUnmanaged,
			(RunnerImpl::ProgressCallback)(void*)setValueUnmanaged);

		GC::KeepAlive(setValue);
        GC::KeepAlive(cancel);
    }


	virtual property double Result 
	{
		double get() override { return result; }
	};
};

}
